<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            width: 100%;
            height: 100vh;
            background-color: #d1c9c9;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: row;
        }

        .center {
            width: 70%;
            height: 100%;
            background-color: #dbdbdb;
            /* display: flex;
            justify-content: center;
            align-items: center; */
            display: block;
            overflow: scroll;
        }

        .option {
            width: 30%;
            height: 100%;
            overflow: scroll;
            background-color: #f8f2e5;
            display: block;
            /* justify-content: center;
            align-items: center;
            flex-direction: column; */
        }

        .option-item {
            display: flex;
            justify-content: flex-start;
            margin: 5px;
            width: 90%;
        }

        #canvasP canvas {
            border: 1px solid #fefefe !important;
        }

        .input1 {
            width: 20%;
        }

        .value {
            display: block;
            width: 100%;
            padding: 10px;
            box-sizing: border-box;
        }

        .value-item {
            display: inline-block;
            margin: 10px;
            padding: 15px;
            border: 1px solid #b6b1b1;

        }
    </style>
</head>

<body>

    <div class="box">
        <div class="center" id="canvasP">
            <!-- <canvas id="myCanvas" width="400" height="400"></canvas> -->
        </div>
        <div class="option">
            <form action="javascript:">
                <div class="option-item">
                    <div style="margin: 5px;">画布宽度</div>
                    <input type="number" name="CanvasWeight" id="CanvasWeight" min="200" value="500">
                </div>
                <div class="option2">
                    <div class="option-item" id="optionItem">
                        <div style="margin: 5px;" class="title">定点1</div>
                        <input type="number" name="" id="" class="input1" min="0">
                        <input type="number" name="" id="" class="input1" min="0">-
                        <input type="number" name="" id="" class="input1" min="0">
                        <input type="number" name="" id="" class="input1" min="0">
                    </div>
                </div>
                <div class="option-item">
                    <div style="margin: 5px;">圆形半径</div>
                    <input type="number" name="arc" id="arc" min="10" value="20">
                </div>
                <div class="option-item">
                    <div style="margin: 5px;">递进长度</div>
                    <input type="number" name="addValue" id="addValue" min="1" value="10">
                </div>
                <div class="option-item">
                    <button type="submit">绘制图形</button>
                    <button type="reset">重置</button>
                </div>
            </form>
            <div class="value">
                <!-- <div class="value-item " onclick="setFormValue()"></div> -->
            </div>
        </div>
    </div>

    <script src="./jquery.3.5.1.js"></script>
    <!-- <script src="../../js/jquery.3.5.1.js"></script> -->
    <!-- <script src="../../js/konva.js"></script> -->
    <script>
        class Local {
            constructor() {
                this.initLo();
            }
            setData(key, value) { // 保存键值对到本地
                if (typeof value === 'string') {
                    return localStorage.setItem(key, value);
                }
                try {
                    localStorage.setItem(key, JSON.stringify(value));
                } catch (err) {
                    return err;
                }
            }
            getData(key) { // 获取指定key的数据
                const value = localStorage.getItem(key);
                try {
                    return JSON.parse(value);
                } catch (err) {
                    return value;
                }
            }
            removeData(key) { // 删除指定key的数据
                return localStorage.removeItem(key);
            }
            clearData() { // 删除所有的本地数据
                return localStorage.clear();
            }
            initLo() { // 初始化
                if (!window.localStorage) {
                    throw new Error("浏览器不支持 localstorage 本地存储！！！")
                }
            }
        }
        var local = new Local()

        function setData(data) {
            return local.setData('test', data)
        }

        function getData(data) {
            return local.getData('test')
        }
    </script>
    <script>
        var tipList = {},
            CanvasWeight = 200,
            arc = 10,
            addValue = 10
        for (let index = 0; index < 8; index++) {
            var clone = $("#optionItem").clone()
            clone.find('.title').text('位置' + (index + 1))
            clone.find('.input1').each(function (index2, item) {
                $(this).attr("name", 'input-' + (index + 1) + '-' + (index2 + 1))
            })
            $('.option2').append(clone)
        }
        $('#optionItem').remove()
        // $('.option-item:eq(3)').find('input').each(function (index, item) {
        //     $(this).attr('disabled', true)
        // })
        // $('.option-item:eq(7)').find('input').each(function (index, item) {
        //     $(this).attr('disabled', true)
        // })
        $('.option-item:eq(3)').hide()
        $('.option-item:eq(7)').hide()

        $("form").submit(function (e) {
            // console.log('', $('form').serializeArray())
            var form = $('form').serializeArray()
            $("#canvasP").html('')

            var data = getData() ? getData() : []
            data.push(form)
            setData(data)
            setTest()

            // setValue(form)
            location.reload()

            // console.log('', tipList)
        });

        // 格式化表单的值
        function setValue(form) {
            CanvasWeight = Number(form[0].value)
            arc = Number(form[33].value)
            addValue = Number(form[34].value)
            for (let index = 1; index < form.length; index++) {
                var ele = form[index];
                // if (ele) continue;
                var splitList = ele.name.split('-')
                if (!tipList[splitList[1]]) tipList[splitList[1]] = {
                    from: [0, 0],
                    to: [0, 0],
                }
                if (splitList[2] == '1') tipList[splitList[1]]['from'][0] = Number(ele.value)
                if (splitList[2] == '2') tipList[splitList[1]]['from'][1] = Number(ele.value)
                if (splitList[2] == '3') tipList[splitList[1]]['to'][0] = Number(ele.value)
                if (splitList[2] == '4') tipList[splitList[1]]['to'][1] = Number(ele.value)
            }
            // var rule1Value = rule1(tipList[1]['from'][0], tipList[1]['from'][1], tipList[4]['from'][0], tipList[4][
            //     'from'
            // ][1], 0, null)
            // if (!rule1Value) {
            //     alert("定点1和定点4不能平行")
            //     return;
            // }
            // tipList[3]['from'] = rule1Value
            // rule1Value = rule1(tipList[1]['from'][0], tipList[1]['from'][1], tipList[6]['from'][0], tipList[6]['from'][
            //     1
            // ], 0, null)
            // if (!rule1Value) {
            //     alert("定点1和定点4不能平行")
            //     return;
            // }
            // tipList[7]['from'] = rule1Value
            forSerCanvas(tipList)
        }
        // 点击赋值的展示
        setTest()

        function setTest() {
            var data = getData()
            if (!data) return;
            $('.value').html('')
            $.each(data, function (ii, item) {
                // console.log('', ii, item)
                $('.value').append(`<div class="value-item " onclick="setFormValue(${ii})">${ii + 1}</div>`)
            })
        }
        // 点击给表单赋值
        function setFormValue(e) {
            var data = getData()
            var formData = data[e]
            // console.log('', formData)
            formData.forEach(function (item) {
                $(`[name="${item.name}"]`).val(item.value)
            })
        }


        var total = [];
        addValue = addValue || 5;
        // 循环排列，尽可能的排列出所有值
        function forSerCanvas(tipList) {
            var arr = []
            Object.keys(tipList).forEach(function (item) {
                if (Number(item) && (tipList[item]['to'][0] != 0 || tipList[item]['to'][1] != 0)) {
                    arr.push(item)
                }
            })
            var combination = combination2(arr)
            // console.log('', combination)
            for (let index = 0; index < combination.length; index++) {
                const element = combination[index];
                var itemList = element.split('')
                setCanvasValueEnd(itemList, JSON.parse(JSON.stringify(tipList)), 0)
            }
            function setCanvasValueEnd(itemList, obj, flag = false) {
                for (let index = 0; index < itemList.length; index++) {
                    const item = itemList[index];
                    if (obj[item]['to'][0] != 0) { // x 轴
                        if (obj[item]['to'][0] < obj[item]['from'][0]) {
                            addValue = addValue * -1
                        }
                        if (obj[item]['from'][0] + addValue <= obj[item]['to'][0] && addValue > 0) {
                            obj[item]['from'][0] = obj[item]['from'][0] + addValue
                            flag = true
                        }
                        if (obj[item]['from'][0] + addValue >= obj[item]['to'][0] && addValue < 0) {
                            obj[item]['from'][0] = obj[item]['from'][0] + addValue
                            flag = true
                        }
                    }
                    if (obj[item]['to'][1] != 0) { // y 轴
                        if (obj[item]['to'][1] < obj[item]['from'][1]) {
                            addValue = addValue * -1
                        }
                        if (obj[item]['from'][1] + addValue <= obj[item]['to'][1] && addValue > 0) {
                            obj[item]['from'][1] = obj[item]['from'][1] + addValue
                            flag = true
                        }
                        if (obj[item]['from'][1] + addValue >= obj[item]['to'][1] && addValue < 0) {
                            obj[item]['from'][1] = obj[item]['from'][1] + addValue
                            flag = true
                        }
                    }
                    addValue = Math.abs(addValue);
                }
                if (flag) {

                    // 验证规则
                    // 验证上边内侧的两个点的位置
                    var rule1Value = rule1(obj[1]['from'][0], obj[1]['from'][1], obj[4]['from'][0], obj[4][
                        'from'
                    ][1], null, 1)
                    if (!rule1Value) {
                        // alert("定点1和定点4不能平行")
                        setCanvasValueEnd(itemList, obj)
                        return;
                    }
                    obj[3]['from'] = rule1Value
                    rule1Value = rule1(obj[1]['from'][0], obj[1]['from'][1], obj[6]['from'][0], obj[6]['from'][
                        1
                    ], null, 1)
                    if (!rule1Value) {
                        // alert("定点1和定点4不能平行")
                        setCanvasValueEnd(itemList, obj)
                        return;
                    }
                    obj[7]['from'] = rule1Value

                    // // 验证曲线的终点和起点是否在范围内
                    rule1Value = rule2(obj[1]['from'][0], obj[1]['from'][1], obj[2]['from'][0], obj[2]['from'][
                        1
                    ], obj[4]['from'][0], obj[4]['from'][1])
                    if (rule1Value && rule1Value[0] > obj[4]['from'][0]) {
                        setCanvasValueEnd(arr, obj)
                        return;
                        // console.log('曲线的起点不在范围内');
                    }
                    rule1Value = rule2(obj[1]['from'][0], obj[1]['from'][1], obj[8]['from'][0], obj[8]['from'][
                        1
                    ], obj[4]['from'][0], obj[4]['from'][1])
                    if (rule1Value && rule1Value[0] < obj[4]['from'][0]) {
                        setCanvasValueEnd(arr, obj)
                        return;
                        // console.log('曲线的起点不在范围内');
                    }
                    rule1Value = rule2(obj[1]['from'][0], obj[1]['from'][1], obj[8]['from'][0], obj[8]['from'][
                        1
                    ], obj[6]['from'][0], obj[6]['from'][1])
                    if (rule1Value && rule1Value[0] < obj[6]['from'][0]) {
                        setCanvasValueEnd(arr, obj)
                        return;
                        // console.log('曲线的终点不在范围内');
                    }
                    rule1Value = rule2(obj[1]['from'][0], obj[1]['from'][1], obj[2]['from'][0], obj[2]['from'][
                        1
                    ], obj[6]['from'][0], obj[6]['from'][1])
                    if (rule1Value && rule1Value[0] > obj[6]['from'][0]) {
                        setCanvasValueEnd(arr, obj)
                        return;
                        // console.log('曲线的终点不在范围内');
                    }

                    // // 曲线的终点大于启点
                    if (obj[4]['from'][0] >= obj[6]['from'][0]) {
                        setCanvasValueEnd(arr, obj)
                        return;
                        // console.log('曲线的终点不在范围内');
                    }
                    // 曲线控制点
                    if (obj[5]['from'][0] < obj[4]['from'][0] || obj[5]['from'][1] < obj[4]['from'][1]) {
                        setCanvasValueEnd(arr, obj)
                        return;
                        // console.log('曲线的终点不在范围内');
                    }
                    if (obj[5]['from'][0] > obj[6]['from'][0] || obj[5]['from'][1] < obj[6]['from'][1]) {
                        setCanvasValueEnd(arr, obj)
                        return;
                        // console.log('曲线的终点不在范围内');
                    }

                    // 画圆，确定园的圆心
                    var x = (obj[8]['from'][0] + obj[2]['from'][0]) / 2;
                    var y = (obj[8]['from'][1] + obj[2]['from'][1]) / 2;
                    var height = arc || 20; // 圆半径
                    rule1Value = rule1(obj[1]['from'][0], obj[1]['from'][1], x, y, null, CanvasWeight - height)
                    // console.log('rule1Value', rule1Value);
                    obj['arc'] = [rule1Value[0], rule1Value[1], height]


                    var tepObj = JSON.parse(JSON.stringify(obj))
                    // console.log('', tepObj[1])
                    total.push(tepObj)
                    setCanvasValueEnd(itemList, obj)
                }
            }
            total.forEach(function (item) {
                setCanvas(item)
            })
        }

        // // var total = [];
        // addValue = addValue || 5;
        // // 循环排列，尽可能的排列出所有值
        // function forSerCanvas(tipList) {
        //     // console.log('', tipList)
        //     var combination = combination2()
        //     // console.log('', combination)
        //     for (let index = 0; index < combination.length; index++) {
        //         const element = combination[index];
        //         var itemList = element.split('')
        //         setCanvasValueEnd(itemList, Object.assign({}, tipList), 0)
        //     }
        //     // console.log('total', total)

        //     function setCanvasValueEnd(arr, obj, indexStart) {
        //         var flag = false;
        //         for (let index = indexStart; index < arr.length; index++) {
        //             const item = arr[index];
        //             // console.log('====', item, index)

        //             if (obj[item]['to'][0] != 0) { // x 轴
        //                 if (obj[item]['to'][0] < obj[item]['from'][0]) {
        //                     addValue = -addValue
        //                 }
        //                 if (obj[item]['from'][0] <= obj[item]['to'][0]) {
        //                     obj[item]['from'][0] = obj[item]['from'][0] + addValue
        //                     flag = true
        //                 }
        //             }
        //             if (obj[item]['to'][1] != 0) { // y 轴
        //                 if (obj[item]['to'][1] < obj[item]['from'][1]) {
        //                     addValue = -addValue
        //                 }
        //                 if (obj[item]['from'][1] <= obj[item]['to'][1]) {
        //                     obj[item]['from'][1] = obj[item]['from'][1] + addValue
        //                     flag = true
        //                 }
        //             }
        //             if (flag) {
        //                 // 验证规则
        //                 // 验证上边内侧的两个点的位置
        //                 var rule1Value = rule1(obj[1]['from'][0], obj[1]['from'][1], obj[4]['from'][0], tipList[4][
        //                     'from'
        //                 ][1], 0, null)
        //                 if (!rule1Value) {
        //                     alert("定点1和定点4不能平行")
        //                     return;
        //                 }
        //                 tipList[3]['from'] = rule1Value
        //                 rule1Value = rule1(obj[1]['from'][0], obj[1]['from'][1], obj[6]['from'][0], tipList[6]['from'][
        //                     1
        //                 ], 0, null)
        //                 if (!rule1Value) {
        //                     alert("定点1和定点4不能平行")
        //                     return;
        //                 }
        //                 tipList[7]['from'] = rule1Value
        //                 // 验证曲线的终点和起点是否在范围内
        //                 rule1Value = rule2(obj[1]['from'][0], obj[1]['from'][1], obj[2]['from'][0], tipList[2]['from'][
        //                     1
        //                 ], obj[4]['from'][0], tipList[4]['from'][1])
        //                 if (rule1Value[0] > obj[4]['from'][0]) {
        //                     setCanvasValueEnd(arr, obj, ++index)
        //                     // console.log('曲线的起点不在范围内');
        //                     continue;
        //                 }
        //                 rule1Value = rule2(obj[1]['from'][0], obj[1]['from'][1], obj[8]['from'][0], tipList[8]['from'][
        //                     1
        //                 ], obj[6]['from'][0], tipList[6]['from'][1])
        //                 if (rule1Value[0] < obj[6]['from'][0]) {
        //                     setCanvasValueEnd(arr, obj, ++index)
        //                     // console.log('曲线的终点不在范围内');
        //                     continue;
        //                 }

        //                 // 曲线的终点大于启点
        //                 if (obj[4]['from'][0] >= obj[6]['from'][0]) {
        //                     setCanvasValueEnd(arr, obj, ++index)
        //                     // console.log('曲线的终点不在范围内');
        //                     continue;
        //                 }

        //                 // 画圆，确定园的圆心
        //                 var x = (obj[8]['from'][0] + obj[2]['from'][0]) / 2;
        //                 var y = (obj[8]['from'][1] + obj[2]['from'][1]) / 2;
        //                 var height = arc || 20; // 圆半径
        //                 rule1Value = rule1(obj[1]['from'][0], obj[1]['from'][1], x, y, null, CanvasWeight - height)
        //                 // console.log('rule1Value', rule1Value);
        //                 obj['arc'] = [rule1Value[0], rule1Value[1], height]

        //                 setCanvas(Object.assign({}, obj))
        //                 // total.push(Object.assign({}, obj))
        //                 setCanvasValueEnd(arr, obj, ++index)
        //             }
        //         }
        //     }
        // }



        // 限定规则1（两点式）：根据已知两点，确定第三点的坐标
        function rule1(x1, y1, x2, y2, x, y) {
            if (x1 == x2) {
                // return [x1, 0]
                return null;
            }
            if (y1 == y2) {
                // console.error("y轴平行了")
                return null;
            }
            if (!x) {
                x = (y - y1) * (x2 - x1) / (y2 - y1) + x1
            }
            if (!y) {
                y = (x - x1) * (y2 - y1) / (x2 - x1) + y1;
            }
            return [x, y]
        }

        // 计算一个点和一条直线的垂直线的交点
        function rule2(x1, y1, x2, y2, x3, y3) {
            // 判断要计算的点是否在直线上
            if ((y2 - y1) * (x3 - x1) == (y3 - y1) * (x2 - x1)) {
                return null
            }
            // 判断直线是否和x轴垂直
            k = (y2 - y1) / (x2 - x1);
            var x = (x1 + x3 + (y3 / k) - (y1 / k)) / 2;
            var y = k * (x - x1) + y1
            return [x, y]
        }



        var count = 1; // 每次增加量
        var KonvaObj = {}

        function setCanvas(form) {
            $('#canvasP').append(
                `<canvas id="canvas-${count}" width="${CanvasWeight}" height="${CanvasWeight}" style="display: inline-flex;margin: 10px;"></canvas>`
            )
            var canvas = document.getElementById(`canvas-${count}`);
            if (canvas.getContext) {
                var context = canvas.getContext('2d');

                context.beginPath();
                context.moveTo(form[1]['from'][0], Number(form[1]['from'][1]));
                context.lineTo(form[2]['from'][0], form[2]['from'][1]);
                context.lineTo(form[3]['from'][0], form[3]['from'][1]);
                context.lineTo(form[4]['from'][0], form[4]['from'][1]);
                context.quadraticCurveTo(form[5]['from'][0], form[5]['from'][1], form[6]['from'][0],
                    form[6]['from'][1]);
                context.lineTo(form[7]['from'][0], form[7]['from'][1]);
                context.lineTo(form[8]['from'][0], form[8]['from'][1]);
                context.closePath();
                // context.fillStyle = '#' + Math.floor(Math.random() * 16777215).toString(16);
                context.fillStyle = '#cc4057';
                context.fill();

                // 相反方向
                context.beginPath();
                context.moveTo(CanvasWeight - form[1]['from'][0], form[1]['from'][1]);
                context.lineTo(CanvasWeight - form[2]['from'][0], form[2]['from'][1]);
                context.lineTo(CanvasWeight - form[3]['from'][0], form[3]['from'][1]);
                context.lineTo(CanvasWeight - form[4]['from'][0], form[4]['from'][1]);
                context.quadraticCurveTo(CanvasWeight - form[5]['from'][0], form[5]['from'][1], CanvasWeight - form[6][
                    'from'
                ][0], form[6]['from'][1]);
                context.lineTo(CanvasWeight - form[7]['from'][0], form[7]['from'][1]);
                context.lineTo(CanvasWeight - form[8]['from'][0], form[8]['from'][1]);
                context.closePath();
                // context.fillStyle = '#' + Math.floor(Math.random() * 16777215).toString(16);
                context.fillStyle = '#cc4057';
                context.fill();

                // 圆弧路径
                context.beginPath();
                context.arc(form['arc'][0], form['arc'][1], form['arc'][2], 0, 2 * Math.PI);
                context.fillStyle = '#' + Math.floor(Math.random() * 16777215).toString(16);
                // context.fillStyle = '#' + Math.floor(Math.random() * 16777215).toString(16);
                context.fillStyle = '#cc4057';
                context.fill();
                context.closePath();

                context.beginPath();
                context.arc(CanvasWeight - form['arc'][0], form['arc'][1], form['arc'][2], 0, 2 * Math.PI);
                // context.fillStyle = '#' + Math.floor(Math.random() * 16777215).toString(16);
                context.fillStyle = '#cc4057';
                context.fill();
                context.closePath();
            }

            count++;

        }



        (function () {
            var data = getData();
            if (!data) return;
            CanvasWeight = Number(data[data.length - 1][0].value)
            setFormValue(data.length - 1)

            setValue(data[data.length - 1])
        })()

        // 组合
        // combination2()
        function combination2(arr) {
            var result = new Array(); //保存所有组合的数组  
            function getAllComb(myarr) {
                var len = myarr.length;
                for (var i = 1; i <= len; i++)
                    getComb(myarr, len, i);
                // document.write("数组(" + myarr.join(",") + ")的所有的组合(共" + result.length + "种)如下：<hr>" + result.join("\t"));
            }

            //从数组myarr(n)中任选m个元素的所有组合(m>=1 && m<=n)。  
            function getComb(myarr, n, m, rs) {
                if (rs == null)
                    rs = new Array();
                for (var i = n; i >= m; i--) {
                    rs[m - 1] = myarr[i - 1]; //取出第n个元素作为组合的第一个元素  
                    if (m > 1)
                        getComb(myarr, i - 1, m - 1, rs); //递归，在n-1个元素中取m-1个元素,直到取出最后一个元素  
                    var comb = rs.join(""); //获得一个组合  
                    if (!checkExist(result, comb))
                        result.push(comb);
                }
            }

            //查找某元素是否存在数组中,存在返回true,不存在返回false  
            function checkExist(myarr, e) {
                for (var i = 0; i < myarr.length; i++)
                    if (e == myarr[i]) return true;
                return false;
            }

            //测试  
            arr = arr || new Array(1, 2, 4, 5, 6, 8);
            getAllComb(arr);
            // console.log('', result)
            return result;
        }
    </script>
</body>

</html>